///////////////////////////////////////////////////////////////////////////////////////////////////
// Illusion Ray Development Kit (IDK)           Copyright (c) 2010 ( dimitriy.martynenko@gmail.com )
///////////////////////////////////////////////////////////////////////////////////////////////////
// Created : 2010-05-22
// Updated : ...
// Licence : NEW BSD
// Info	   : "SCL" Safe Code Lib (for C++ unmanaged)
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once

namespace System
{
	//TEMP SOLUTION
	struct DefualtDeviceConfig
	{
		enum
		{
			ScreenWidth = 640,
			ScreenHeight = 480
		};
	};

#define DebugBreak __asm { int 3 }

	//
	//
	//		common typedef 

	// TODO: support using x64bit 
	//typedef int					int;
	typedef unsigned	int			uint;

	typedef signed		char		int8;
	typedef unsigned	char		uint8;

	typedef signed		short		int16;
	typedef unsigned	short		uint16;

	typedef unsigned	long		dword;


	typedef				void*		UnSafePtr;
	typedef	const		void*		UnSafeConstPtr;

//#	define				NULL		(UnSafePtr)0
	static const		uint		Invalid(uint(-1));

//#	define DEBUG_OPTIMIZE

#	if defined(DEBUG) | defined(_DEBUG)
#		if	defined(DEBUG_OPTIMIZE)
#			define CheckPtr(X)
#		else //defined(DEBUG_OPTIMIZE)
#			define CheckPtr(X) if(!X) { iError(#X); }
#		endif
#	else //defined(DEBUG) | defined(_DEBUG)
#		define CheckPtr(X)
#	endif

#	define Warning(X) //#pragma warning(X)

	/*-------------------------------------------------------------------------
	| IObject:
	| ------------
	| the base interface for provider ref counter
	---------------------------------------------------------------------------*/
	struct IObject
	{
		virtual void _AddRef(void) = 0;
		virtual void _Release(void) = 0;
	};

#	define IDKClass \
	public : \
		virtual void _AddRef(void)  { TObject::_AddRef(); } \
		virtual void _Release(void) { TObject::_Release(); } \
	private: \


#	include <Platform.hpp>
#	include <Math.hpp>

	/*-------------------------------------------------------------------------
	| TObject:
	| ------------
	| the base object on implement intrusive ref counter
	---------------------------------------------------------------------------*/
	class TObject : virtual public IObject
	{
	private:
		Platform::RefCounter mRefCount;
	private:
		TObject(const TObject&);
		TObject& operator=(const TObject&);
	public:
		TObject(void){}

		virtual	~TObject(void){}

		virtual void _AddRef(void)	
		{
#if defined(DEBUG) | defined(_DEBUG)
			Platform::Profiler::Get().AllocCount.AddRef();
#endif
			mRefCount.AddRef();
		}

		virtual void _Release(void)	
		{
#if defined(DEBUG) | defined(_DEBUG)
			Platform::Profiler::Get().AllocCount.Release();
#endif
			if(mRefCount.Release())
			{
				delete this; 
			}
		}

		inline bool IsUnique(void) const
		{ 
			return mRefCount.IsUnique();
		}
	};
	
	/*-------------------------------------------------------------------------
	| Null Pointer:
	| ------------
	| Is nullable type
	---------------------------------------------------------------------------*/
	class ExNullptr
	{
	public:
		template<typename TCast>
		inline TCast* Cast(void) const
		{
			return 0;
		}

		inline static ExNullptr& GetInstance()
		{
			static ExNullptr null_ptr;
			return null_ptr;
		}
	};

	static ExNullptr NullPtr = ExNullptr::GetInstance();

	/*-------------------------------------------------------------------------
	| ref:
	| ------------
	| ref template
	---------------------------------------------------------------------------*/
	template <class T>
	class ref
	{
	protected:
		T * mReference;
	public:
        typedef ref<T> Base;
		typedef T Create; // for create new instance
		typedef T Instance; // for type item of containter

		inline ref(void) : mReference(NullPtr.Cast<T>()){}

		inline ref(ExNullptr &obj) : mReference(obj.Cast<T>()) {}

		inline ref(T*obj) : mReference(obj) { if(mReference) { mReference->_AddRef(); } }

		inline ref(ref const & obj): mReference(obj.mReference){ if(mReference) { mReference->_AddRef(); } }

		~ref(void) 
		{
			if(mReference)
			{
				mReference->_Release();
			}
		}

        inline void Swap(ref<T> & rhs)
		{
			T* tmp = mReference;
			mReference = rhs.mReference;
			rhs.mReference = tmp;
		}

		template<typename TCast>
		inline ref<TCast> As(void)
		{
			//for cast null don't check ptr : CheckPtr(mReference);
			return static_cast<TCast*>(mReference);
		}

		template<class Custom>
		inline bool Equal(const ref<Custom>& eq) const	{ return eq.mReference == mReference; }
		inline bool Equal(const ExNullptr& eq) const	{ return eq.Cast<T>() == mReference; }


		inline ref& Assign(T* rhs)
		{
			ref(rhs).Swap(*this);
			return *this;
		}

		inline ref& Assign(const ref& rhs)
		{
			ref(rhs).Swap(*this);
			return *this;
		}

		/* Operators */
		inline ref& operator = (ref const & rhs)	
		{ 
			ref(rhs).Swap(*this);
			return *this;
		}
		inline ref& operator = (ExNullptr const&)
		{ 
			ref(0).Swap(*this);
			return *this;
		}
		
		inline const T* GetUnmanagedPointer(void) const	{ CheckPtr(mReference); return mReference; }

		inline T* GetUnmanagedPointer(void) 			{ CheckPtr(mReference); return mReference; }

		inline const T* operator ->(void) const			{ return GetUnmanagedPointer(); }
		inline T* operator ->(void) 					{  return GetUnmanagedPointer(); }
		inline const T& operator *(void) const			{ return *GetUnmanagedPointer(); }
		inline T& operator *(void) 						{ return *GetUnmanagedPointer(); }
	};

	typedef ref<TObject> Object;

	template <class T>
	inline bool operator == (ref<T> cls, const ExNullptr& eq)
	{
		return cls.Equal(eq); 
	}

	template <class T>
	inline bool operator !=	(ref<T> cls, const ExNullptr& eq)
	{
		return !cls.Equal(eq);
	}

	/*---------------------------------------------------------------------------
	| Helper Classes
	---------------------------------------------------------------------------*/
#	include <Set.hpp>
#	include <Type.hpp>
#	include <Threading.hpp>
#	include <Collections.hpp>
#	include <String.hpp>

	/*---------------------------------------------------------------------------
	| Default interface's
	---------------------------------------------------------------------------*/
	struct INameable : virtual public IObject
	{
		virtual const String& GetName(void) const = 0;
	};

	template<class T = uint>
	struct IHandleID : virtual public IObject
	{
		virtual T GetID(void) const = 0;
		virtual void SetID(T id) = 0;
	};

	struct IDelegate : virtual public IObject
	{
		virtual void Invoke(void) = 0;
	};
}

using namespace System;
